#ifndef __PROXY_HEADER
#define __PROXY_HEADER

#include "handler_poll.h"
#include "pipe_recv_buff.h"
#include <unistd.h>
#include <sys/select.h>
#include <vector>
#include <iostream>

template<class OJ, class Deserialize, class Handler, class Task>
class Proxy {
private:
	typedef key_t msg_key;
	typedef pthread_t pthread;

	struct ThreadArgs {
		HandlerPoll<Handler, Task> *hp;
		Task task;
		ThreadArgs(HandlerPoll<Handler, Task> *hp_, Task t):
			hp(hp_), task(t) {}
		~ThreadArgs() {}
	};

private:
	// 监听进程通往代理进程的管道fd
	int in_pipe;
	// 通往日志进程的消息队列id
	int msg_id;
	// 句柄池
	HandlerPoll<Handler, Task> *hp;
	// 仿函数：将监听进程发送的管道字节流反序列化，构造Task对象
	Deserialize des_stream_to_task;

	// select需要的成员变量
	// 构造函数中已经赋值，in_pipe+1
	int max_select_fd; 	
	fd_set all_read_set;
	fd_set ready_read_set;
	// select需要的成员变量
	
	// 接收管道数据的缓冲区(接收监听进程的信息)
	PipeRecvBuff prb;
	// 接收管道数据的缓冲区(接收监听进程的信息)

	// 接收句柄写入的评判结果
	// 接收句柄写入的评判结果
private:	
	static void *add_task_to_hp(void *arg);

public:
	Proxy(int inpipe, int out_pipe, int msgid, const char *cookie_dir);
	~Proxy();
	int main_process();
};

template<class OJ, class Deserialize, class Handler, class Task>
Proxy<OJ, Deserialize, Handler, Task>::Proxy(int inpipe, int out_pipe,
		int msgid, const char *cookie_dir): 
		in_pipe(inpipe), msg_id(msgid), max_select_fd(inpipe+1) {	
	
	int n_handler = 5;
	int	max_task_que = 10;
	/*
	for (int i = 0; i < n_handler; i++) {
		int *p = new int[2];
		pipe(p);
		set_non_blocking(p[0]);
		set_non_blocking(p[1]);
		pipe_vec.push_back(p);
	}
	prb_vec = new PipeRecvBuff[n_handler];
	*/
	hp = new HandlerPoll<Handler, Task>(n_handler, max_task_que, out_pipe, msgid, cookie_dir);
}

template<class OJ, class Deserialize, class Handler, class Task>
Proxy<OJ, Deserialize, Handler, Task>::~Proxy() {
	delete hp;
}

template<class OJ, class Deserialize, class Handler, class Task>
void* Proxy<OJ, Deserialize, Handler, Task>::add_task_to_hp(void *arg) {
	ThreadArgs *targ = (ThreadArgs*)arg;
	HandlerPoll<Handler, Task> *hp = targ->hp;
	Task task = targ->task;
	delete targ;
	hp->add_task(task);
	//printf("proxy: static function add_task_to_hp return\n");
}

template<class OJ, class Deserialize, class Handler, class Task>
int Proxy<OJ, Deserialize, Handler, Task>::main_process() {
	hp->start();

	FD_ZERO(&all_read_set);
	FD_SET(in_pipe, &all_read_set);
	/*
	for (int i = 0; i < pipe_vec.size(); i++) {
		FD_SET(pipe_vec[i][0], &all_read_set);
	}
	*/

	while (true) {
		ready_read_set = all_read_set;
		select(max_select_fd, &ready_read_set, NULL, NULL, NULL);
		//printf("select return\n");
		if (FD_ISSET(in_pipe, &ready_read_set)) {
			if (!prb.finish_length()) {
				prb.recv_length(in_pipe);
				if (prb.finish_length()) {
					prb.get_length();
				}
			}
			if (prb.finish_length() && !prb.finish_data()) {
				prb.recv_data(in_pipe);
			}
			
			if (prb.finish_data()) {
				printf("proxy: pbuff status 2: %s %s\n", prb.length_buff, prb.data_buff);
				Task task = des_stream_to_task(prb.data_buff);
				printf("des_stream_to_task return\n");
				prb.reset();

				ThreadArgs *targs = new ThreadArgs(hp, task);
				pthread ptid;
				pthread_create(&ptid, NULL, add_task_to_hp, (void*)targs);
			}
		}

		// 下一版本开发
		//else if (FD_ISSET(out_pipe, &write_ready_set)) {}
		/*
		else {
			for (int id = 0; id < pipe_vec.size(); id++) {
				if (!FD_ISSET(pipe_vec[id][0], &ready_read_set)) continue;
				
			}		
		}
		*/
	}
}


#endif // __PROXY_HEADER
